#!/usr/bin/env perl
require 5.008;
use warnings;
use strict;

unshift(@INC, '.');
require qpdf_test_helpers;

chdir("qpdf") or die "chdir testdir failed: $!\n";

require TestDriver;

cleanup();

my $td = new TestDriver('linearization');

my $n_tests = 0;
# $n_tests incremented after initialization of @linearized_files and
# @to_linearize.

# *'ed files were linearized with Pdlin.
my @linearized_files =
    ('lin0',                    #   not linearized
     'lin1',                    # * outlines, page labels, pdlin
     'lin2',                    # * lin1 with null and newline
     'lin3',                    #   same file saved with acrobat
     'lin4',                    # * lin1 with no /PageMode
     'lin5',                    #   lin3 with embedded thumbnails
     'lin6',                    # * lin5 with pdlin
     'lin7',                    #   lin5 with /PageMode /UseThumbs
     'lin8',                    # * lin7 with pdlin
     'lin9',                    # * shared objects, indirect null
     'badlin1',                 #   parameter dictionary errors
     );

my @to_linearize =
    ('lin-special',             # lots of weird cases -- see file comments
     'delete-and-reuse',        # deleted, reused objects
     'lin-delete-and-reuse',    # linearized, then delete and reuse
     'object-stream',           # contains object streams
     'hybrid-xref',             # contains both xref tables and streams
     'gen1',                    # has objects with generation > 0 and dangling references
     'gen1-no-dangling',        # has objects with generation > 0
     'direct-outlines',         # /Outlines is a direct object
     @linearized_files,         # we should be able to relinearize
     );

$n_tests += @linearized_files + 6;
$n_tests += (3 * @to_linearize * 5) + 7;

foreach my $base (@linearized_files)
{
    $td->runtest("dump linearization: $base",
                 {$td->COMMAND => "qpdf --show-linearization $base.pdf"},
                 {$td->FILE => "$base.out",
                  $td->EXIT_STATUS => ($base eq 'lin0' ? 0 : 3)},
                 $td->NORMALIZE_NEWLINES);
}

# Check normal modified and linearized modified files, making sure
# that their qdf files are identical.  The next two tests have the
# same expected output files and different input files.
check_pdf($td, "modified",
          "qpdf --static-id --qdf --no-original-object-ids" .
          " delete-and-reuse.pdf", "delete-and-reuse.qdf",
          0);
check_pdf($td, "linearized and modified",
          "qpdf --static-id --qdf --no-original-object-ids" .
          " lin-delete-and-reuse.pdf", "delete-and-reuse.qdf", # same output
          0);

$td->runtest("check linearized and modified",
             {$td->COMMAND => "qpdf --check lin-delete-and-reuse.pdf"},
             {$td->FILE => "lin-delete-and-reuse-check.out",
              $td->EXIT_STATUS => 0},
             $td->NORMALIZE_NEWLINES);
$td->runtest("check multiple modifications",
             {$td->COMMAND => "qpdf --check delete-and-reuse.pdf"},
             {$td->FILE => "delete-and-reuse-check.out",
              $td->EXIT_STATUS => 0},
             $td->NORMALIZE_NEWLINES);

foreach my $base (@to_linearize)
{
    foreach my $omode (qw(disable preserve generate))
    {
        my $oarg = "-object-streams=$omode";
        my $sdarg = "";
        if (($base eq 'lin-special') || ($base eq 'object-stream'))
        {
            $sdarg = "--stream-data=uncompress";
        }
        unlink "a.pdf", "b.pdf", "c.pdf";
        $td->runtest("linearize $base ($omode)",
                     {$td->COMMAND =>
                          "qpdf -linearize $oarg $sdarg" .
                          " --static-id $base.pdf a.pdf"},
                     {$td->STRING => "", $td->EXIT_STATUS => 0});
        $td->runtest("check linearization",
                     {$td->COMMAND => "qpdf --check-linearization a.pdf"},
                     {$td->STRING => "a.pdf: no linearization errors\n",
                      $td->EXIT_STATUS => 0},
                     $td->NORMALIZE_NEWLINES);
        # Relinearizing twice should produce identical results.  We
        # have to do it twice because, if objects changed ordering
        # during the original linearization, the hint tables won't
        # exactly match.  This is because object identifiers are
        # inserted into the hint table in their original order since
        # we don't yet have renumbering information when we compute
        # the table values.
        $td->runtest("relinearize $base 1",
                     {$td->COMMAND =>
                          "qpdf -linearize $sdarg --static-id a.pdf b.pdf"},
                     {$td->STRING => "", $td->EXIT_STATUS => 0});
        $td->runtest("relinearize $base 2",
                     {$td->COMMAND =>
                          "qpdf -linearize $sdarg --static-id b.pdf c.pdf"},
                     {$td->STRING => "", $td->EXIT_STATUS => 0});
        $td->runtest("compare files ($omode)",
                     {$td->FILE => "b.pdf"},
                     {$td->FILE => "c.pdf"});
        if (($base eq 'lin-special') || ($base eq 'object-stream'))
        {
            $td->runtest("check $base ($omode)",
                         {$td->FILE => "a.pdf"},
                         {$td->FILE => "$base.$omode.exp"});
        }
    }
}

$td->runtest("suppress linearization warnings",
             {$td->COMMAND => "qpdf --no-warn --check lin3.pdf"},
             {$td->FILE => "lin3-check-nowarn.out", $td->EXIT_STATUS => 3},
             $td->NORMALIZE_NEWLINES);

cleanup();
$td->report($n_tests);
